﻿#include "effect.h"

EffectsManager effects;

void Effect::Render(CL_GraphicContext &gc)
{
	if (!appearance->Render(gc, this)) active=0; // Возвращает false если эффект отработал своё
}

void Effect::Update(float time)
{
	behaviour->Update(this, time);
}

EffectsManager::EffectsManager() :
_effects(0), id_index_table(0), active_effects_count(0), next_free_id_slot(0)
{
	_effects = new Effect[MAX_EFFECTS];
	id_index_table=new unsigned int[MAX_EFFECTS];
	// initialize the ID-index-table to form a linked list, each entry pointing to the free bullet
	for(unsigned int t=0;t<MAX_EFFECTS;++t) id_index_table[t]=t+1;
}

EffectsManager::~EffectsManager()
{
	delete[] id_index_table;
	delete[] _effects;
}

unsigned int EffectsManager::Create(Effect &p_effect_description)
{
	Effect &l_new_effect=_effects[active_effects_count];
	l_new_effect = p_effect_description;
	l_new_effect.active = 1;
	l_new_effect.time_lived = 0;
	unsigned int l_id=next_free_id_slot;
	l_new_effect.id=l_id;
	// remember: next_free_id_slot contains the index of the next free ID, see initialization
	// now we store that index to the free ID list for the next bullet that's going to be created later...
	next_free_id_slot=id_index_table[l_id];
	// ... and instead let the table now point to our bullet's array index!
	id_index_table[l_id]=active_effects_count++;
	//cl_log_event("Debug", "Effect created!");
	return l_id;
}

unsigned int EffectsManager::CreateBulletEffect(Bullet &bullet, int type)
{
	Effect &l_new_effect=_effects[active_effects_count];
	l_new_effect.active = 1;
	l_new_effect.time_lived = 0;
	l_new_effect.position = bullet.position;
	l_new_effect.direction = bullet.direction;
	l_new_effect.speed = bullet.speed;
	l_new_effect.appearance_index = bullet.appearance_index;
	// id
	unsigned int l_id=next_free_id_slot;
	l_new_effect.id=l_id;
	next_free_id_slot=id_index_table[l_id];
	id_index_table[l_id]=active_effects_count++;
	// И определим исходя из заданного типа
	if (type == 0)
	{
		// Отменённые пули
		l_new_effect.appearance = renders.GetEffectRender("cancelled_bullet");
		l_new_effect.behaviour = patterns.GetEffectBehaviour("effect_stay_still");
	}
	else if (type == 1)
	{
		// Уничтоженная пуля игрока типа 1
		l_new_effect.appearance = renders.GetEffectRender("player_bullet_hit1");
		l_new_effect.behaviour = patterns.GetEffectBehaviour("effect_stay_still");
	}
	else if (type == 2)
	{
		// Уничтоженная пуля игрока типа 2
		l_new_effect.appearance = renders.GetEffectRender("player_bullet_hit2");
		l_new_effect.behaviour = patterns.GetEffectBehaviour("effect_stay_still");
	}
	else if (type == 3)
	{
		// Отскочившая при попадании частичка
		l_new_effect.appearance = renders.GetEffectRender("particle_small");
		l_new_effect.behaviour = patterns.GetEffectBehaviour("effect_flyoff");
		l_new_effect.appearance_index = 3;
		l_new_effect.speed = bullet.speed * ((float)(rand() % 100) / 200.0f);
		CL_Angle a(bullet.direction.angle(CL_Vec2<float>(1,0)));
		if (bullet.direction.y < 0)
			a = CL_Angle(360, cl_degrees) - a;
		a += CL_Angle(180.0f + (float)(rand() % 100 - 50), cl_degrees);
		l_new_effect.direction = CL_Vec2<float>(cos(a.to_radians()), sin(a.to_radians()));
		l_new_effect.param_float = 0.5f + (float)(rand() % 100) / 200;
	}
	else if (type == 4)
	{
		// Уничтоженная пуля игрока типа 3
		l_new_effect.appearance = renders.GetEffectRender("player_bullet_hit3");
		l_new_effect.behaviour = patterns.GetEffectBehaviour("effect_stay_still");
	}
	// Уничтоженная пуля игрока типа 4
	else if (type == 51)
	{
		l_new_effect.appearance = renders.GetEffectRender("player_bullet_hit4");
		l_new_effect.behaviour = patterns.GetEffectBehaviour("effect_stay_still");
	}
	else if (type == 52)
	{
		l_new_effect.appearance = renders.GetEffectRender("player_bullet_hit5");
		l_new_effect.behaviour = patterns.GetEffectBehaviour("effect_stay_still");
	}
	else if (type == 53)
	{
		l_new_effect.appearance = renders.GetEffectRender("player_bullet_hit6");
		l_new_effect.behaviour = patterns.GetEffectBehaviour("effect_stay_still");
	}
	else if (type == 54)
	{
		l_new_effect.appearance = renders.GetEffectRender("player_bullet_hit7");
		l_new_effect.behaviour = patterns.GetEffectBehaviour("effect_stay_still");
	}
	else if (type == 6)
	{
		// Попавшие пули противника
		l_new_effect.appearance = renders.GetEffectRender("enemy_bullet_hit1");
		l_new_effect.behaviour = patterns.GetEffectBehaviour("effect_stay_still");
		// TO DO - отдельные эффекты для больших пуль
		l_new_effect.appearance_index = bullet.appearance_index;
	}
	return l_id;
}

void EffectsManager::Clear()
{
	active_effects_count = 0;
	next_free_id_slot = 0;
	for(unsigned int t=0;t<MAX_EFFECTS;++t) id_index_table[t]=t+1;
}

void EffectsManager::Update(float time)
{
	unsigned int l_new_index=0;
	for(unsigned int t=0;t<active_effects_count;++t)
	{
		Effect &l_effect = _effects[t];
		l_effect.Update(time);
		if(!l_effect.active)
		{
			id_index_table[l_effect.id]=next_free_id_slot;
			next_free_id_slot=l_effect.id;
		} 
		else
		{
			if(t!=l_new_index)
			{
				_effects[l_new_index]=l_effect;
				id_index_table[l_effect.id]=l_new_index;
			}
			l_new_index++;
		}
	}
	active_effects_count = l_new_index;
}

void EffectsManager::Render(CL_GraphicContext &gc, CL_Rect &clip)
{
	gc.set_cliprect(clip);
	for(unsigned int t=0;t<active_effects_count;++t)
		_effects[t].Render(gc);
	gc.pop_cliprect();
}

Effect& EffectsManager::GetEffectByID(unsigned int p_id)
{
	return _effects[id_index_table[p_id]];
}
